/* Token type */
#define TOKEN_TYPE_KW		0
#define TOKEN_TYPE_ID		1
#define TOKEN_TYPE_CONST_INT	2
#define TOKEN_TYPE_CONST_FLOAT	3
#define TOKEN_TYPE_CONST_SYM	4

/* Key word type */
#define KW_TYPE_TYPE_QUAL	0
#define KW_TYPE_TYPE		1
#define KW_TYPE_BOOL_VAL	2
#define KW_TYPE_FLOW_CTL	3
#define KW_TYPE_PAR_QUAL	4
#define KW_TYPE_ACT		5

/* KW_TYPE_TYPE subtype */
#define KW_TYPE_TYPE_BASIC	0
#define KW_TYPE_TYPE_SAMPLER	1
#define KW_TYPE_TYPE_MAT	2
#define KW_TYPE_TYPE_VEC	3
#define KW_TYPE_TYPE_STRUCT	4

/* KW_TYPE_FLOW_CTL subtype */
#define KW_TYPE_FLOW_WHILE	0
#define KW_TYPE_FLOW_IF		1

/* key word define
 * 31-28  27-24    23-8     7-0
 * type   subtype  reserved id
 */
#define KW_TYPE_SHIFT		28
#define KW_TYPE_MASK		0xf
#define KW_SUBTYPE_SHIFT	24
#define KW_SUBTYPE_MASK		0xf
#define KW_ID_SHIFT		0
#define KW_ID_MASK		0xff
/*TODO: define bit state using reserved bits. */

#define KW(type, subtype, id)\
 ((type << KW_TYPE_SHIFT) | (subtype << KW_SUBTYPE_SHIFT) | (id << KW_ID_SHIFT))

#define KW_attribute	KW(KW_TYPE_TYPE_QUAL, 0, 0)
#define KW_const	KW(KW_TYPE_TYPE_QUAL, 0, 1)
#define KW_uniform	KW(KW_TYPE_TYPE_QUAL, 0, 2)
#define KW_varying	KW(KW_TYPE_TYPE_QUAL, 0, 3)
#define KW_precision	KW(KW_TYPE_TYPE_QUAL, 0, 4)
#define KW_lowp		KW(KW_TYPE_TYPE_QUAL, 0, 5)
#define KW_mediump	KW(KW_TYPE_TYPE_QUAL, 0, 6)
#define KW_highp	KW(KW_TYPE_TYPE_QUAL, 0, 7)
#define KW_invariant	KW(KW_TYPE_TYPE_QUAL, 0, 8)
#define KW_float	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_BASIC, 9);
#define KW_int		KW(KW_TYPE_TYPE, KW_TYPE_TYPE_BASIC, 10)
#define KW_void		KW(KW_TYPE_TYPE, KW_TYPE_TYPE_BASIC, 11)
#define KW_bool		KW(KW_TYPE_TYPE, KW_TYPE_TYPE_BASIC, 12)
#define KW_sampler2D	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_SAMPLER, 13)
#define KW_samplerCube	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_SAMPLER, 14)
#define KW_mat2		KW(KW_TYPE_TYPE, KW_TYPE_TYPE_MAT, 15)
#define KW_mat3		KW(KW_TYPE_TYPE, KW_TYPE_TYPE_MAT, 16)
#define KW_mat4		KW(KW_TYPE_TYPE, KW_TYPE_TYPE_MAT, 17)
#define KW_vec2		KW(KW_TYPE_TYPE, KW_TYPE_TYPE_VEC, 18)
#define KW_vec3		KW(KW_TYPE_TYPE, KW_TYPE_TYPE_VEC, 19)
#define KW_vec4		KW(KW_TYPE_TYPE, KW_TYPE_TYPE_VEC, 20)
#define KW_ivec2	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_VEC, 21)
#define KW_ivec3	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_VEC, 22)
#define KW_ivec4	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_VEC, 23)
#define KW_bvec2	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_VEC, 24)
#define KW_bvec3	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_VEC, 25)
#define KW_bvec4	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_VEC, 26)
#define KW_struct	KW(KW_TYPE_TYPE, KW_TYPE_TYPE_STRUCT, 27)
#define KW_true		KW(KW_TYPE_BOOL_VAL, 0, 28)
#define KW_false	KW(KW_TYPE_BOOL_VAL, 0, 29)
#define KW_break	KW(KW_TYPE_FLOW_CTL, KW_TYPE_FLOW_WHILE, 30)
#define KW_continue	KW(KW_TYPE_FLOW_CTL, KW_TYPE_FLOW_WHILE, 31)
#define KW_do		KW(KW_TYPE_FLOW_CTL, KW_TYPE_FLOW_WHILE, 32)
#define KW_for		KW(KW_TYPE_FLOW_CTL, KW_TYPE_FLOW_WHILE, 33)
#define KW_while	KW(KW_TYPE_FLOW_CTL, KW_TYPE_FLOW_WHILE, 34)
#define KW_if		KW(KW_TYPE_FLOW_CTL, KW_TYPE_FLOW_IF, 35)
#define KW_else		KW(KW_TYPE_FLOW_CTL, KW_TYPE_FLOW_IF, 36)
#define KW_in		KW(KW_TYPE_PAR_QUAL, 0, 37)
#define KW_out		KW(KW_TYPE_PAR_QUAL, 0, 38)
#define KW_inout	KW(KW_TYPE_PAR_QUAL, 0, 39)
#define KW_discard	KW(KW_TYPE_ACT, 0, 40)
#define KW_return	KW(KW_TYPE_ACT, 0, 41)

#define KW_NUM		42


/* Symbols define
 * 31-28  27-24    23-8     7-0
 * type   subtype  reserved id
 */
#define SYM_TYPE_SHIFT		28
#define SYM_TYPE_MASK		0xf
#define SYM_SUBTYPE_SHIFT	24
#define SYM_SUBTYPE_MASK	0xf
#define SYM_ID_SHIFT		0
#define SYM_ID_MASK		0xff
/*TODO: define bit state using reserved bits. */

#define SYM(type, subtype, id) (\
  (type << KW_TYPE_SHIFT) | \
  (subtype << KW_SUBTYPE_SHIFT) | \
  (id << KW_ID_SHIFT))

#define SYM_dot		SYM(0, 0, 0) /* . */
#define SYM_plus	SYM(0, 0, 1) /* + */
#define SYM_minus	SYM(0, 0, 2) /* - */
#define SYM_divide	SYM(0, 0, 3) /* / */
#define SYM_multiply	SYM(0, 0, 4) /* * */
#define SYM_mod		SYM(0, 0, 5) /* % */
#define SYM_less	SYM(0, 0, 6) /* < */
#define SYM_more	SYM(0, 0, 7) /* > */
#define SYM_lsquare	SYM(0, 0, 8) /* [ */
#define SYM_rsquare	SYM(0, 0, 9) /* ] */
#define SYM_lround	SYM(0, 0, 10) /* ( */
#define SYM_rround	SYM(0, 0, 11) /* ) */
#define SYM_lbrace	SYM(0, 0, 12) /* { */
#define SYM_rbrace	SYM(0, 0, 13) /* } */
#define SYM_bxor	SYM(0, 0, 14) /* ^ */
#define SYM_bor		SYM(0, 0, 15) /* | */
#define SYM_band	SYM(0, 0, 16) /* & */
#define SYM_bnot	SYM(0, 0, 17) /* ~ */
#define SYM_assign	SYM(0, 0, 18) /* = */
#define SYM_not		SYM(0, 0, 19) /* ! */
#define SYM_colon	SYM(0, 0, 20) /* : */
#define SYM_end		SYM(0, 0, 21) /* ; */
#define SYM_comma	SYM(0, 0, 22) /* , */
#define SYM_question	SYM(0, 0, 23) /* ? */
#define SYM_hash	SYM(0, 0, 24) /* # */
#define SYM_inc		SYM(0, 0, 25) /* ++ */
#define SYM_dec		SYM(0, 0, 26) /* -- */
#define SYM_lshift	SYM(0, 0, 27) /* << */
#define SYM_rshift	SYM(0, 0, 28) /* >> */
#define SYM_lessequal	SYM(0, 0, 29) /* <= */
#define SYM_moreequal	SYM(0, 0, 30) /* >= */
#define SYM_equal	SYM(0, 0, 31) /* == */
#define SYM_notequal	SYM(0, 0, 32) /* != */
#define SYM_and		SYM(0, 0, 33) /* && */
#define SYM_xor		SYM(0, 0, 34) /* ^^ */
#define SYM_plusassign	SYM(0, 0, 35) /* += */
#define SYM_minusassign	SYM(0, 0, 36) /* -= */
#define SYM_multiassign	SYM(0, 0, 37) /* *= */
#define SYM_divassign	SYM(0, 0, 38) /* /= */
#define SYM_modassign	SYM(0, 0, 39) /* %= */
#define SYM_lshfassign	SYM(0, 0, 40) /* <<= */
#define SYM_rshfassign	SYM(0, 0, 41) /* >>= */
#define SYM_bandassign	SYM(0, 0, 42) /* &= */
#define SYM_bxorassign	SYM(0, 0, 43) /* ^= */
#define SYM_borassign	SYM(0, 0, 44) /* |= */

/* alloc: user src_next_tocken
 * free: syntax analyzer call tocken_free
 */
typedef struct _Token {
	int type;
	union u {
		struct {
			int value;
		} keyword;
		struct {
			DString *name;
		} id;
		struct {
			int value;
		} const_int;
		struct {
			float value;
		} const_float;
		struct {
			int value;
		} bool_val;
		struct {
			int value;
		} sym;
	};
} Token;

void token_free(Token *tk);

/* alloc: user call src_init
 * free: user call src_free
 */
typedef struct _Source {
	/* source from glShaderSource */
	char **string;
	int count;
	int *length;
	DString *log;

	/* for get_char */
	int curr_cnt;
	int curr_str_num;

	/* used to check whether current identifer ends */
	char next_char;
	/* word index in one line */
	int word_index;

} Source;

Token* src_next_token(Source *src);
